import { LoadingOutlined, ReloadOutlined } from '@ant-design/icons'
import { truthy } from '@gnlab/utils'
import { Tooltip, Checkbox } from 'antd'
import c from 'classnames'
import { ReactComponent as RobotIcon } from '@/desktop/assets/robot.svg'
import { Lazy, LazyTooltip, LazyImage } from '@/desktop/components/lazy'
import  defaultAvatar  from '@/desktop/assets/avatar.jpg'
import formatAssetUrl from '@/desktop/logics/format-asset-url'
import { triggerAt } from '@/desktop/views/chat/editor/at-members'
import services from '@/services'
import type { Account } from '@/services/auth'
import type { ChatRecordType as Type, ChatRecordMap, ChatRecord } from '@/services/contact-chat'
import { type Contact, ContactType } from '@/services/contacts'
import { formatChatTime } from '../utils'
import { Actions, isForwardable, canQuote, doQuote } from './actions'
import { renderers, bareRecordTypes, type Renderer } from './renderers'
import './index.module.less'

export { RecordModals } from './modals'
export type RecordContact = Pick<Contact, 'ownerWxid'> & Partial<Pick<Contact, 'userId' | 'type'>> // 可选字段仅用于部分次要功能，不提供则这些功能不启用

interface RecordProps<T extends Type> {
  id?: string
  className?: string
  sender: { name: string; avatar: string }
  contact: RecordContact // 联系人和 sender 不是一个概念，例如联系人可能是群，sender 是群里发送了这条消息的那个人
  account?: Account
  record: ChatRecordMap[T]
  readonly?: boolean // 是否以只读模式显示（不显示操作行为）
  choosed?: boolean // 有值代表处于“多选”状态，true 选中，false 未选择
  switchChoose?: (record: ChatRecord) => void
}

export function Record<T extends Type>(props: RecordProps<T>) {
  const {
    id,
    className,
    sender,
    contact,
    account,
    record,
    readonly = false,
    choosed,
    switchChoose,
  } = props

  // 是否匹配上了敏感词预警规则
  const hasWarning = !record.isSend && record.matchWarnRules.length > 0

  const bare = bareRecordTypes.has(record.type)
  const Renderer = renderers[record.type] as Renderer<T>
  const rendered = <Renderer record={record} contact={contact} readonly={readonly} />

  return <div
    id={id}
    styleName={c('record', hasWarning && 'warning')}
    className={c(record.isSend ? 'chat-record-send' : 'chat-record-receive', className)}
  >
    {bare ? (
      rendered
    ) : (
      <div styleName="choose-wrap">
        {choosed !== undefined ? (
          <Checkbox
            disabled={!isForwardable(record)}
            checked={choosed}
            onChange={() => switchChoose?.(record)}
          />
        ) : null}
        <div>
          <Info contact={contact} record={record} sender={sender} readonly={readonly} />

          <div styleName="record-main">
            <div styleName="avatar">
              <LazyImage src={formatAssetUrl(sender.avatar) || defaultAvatar} />
            </div>
            <div styleName="content-wrapper">
              {rendered}
              <CommonExtraInfo record={record} />
            </div>
            <SendStatus record={record} />
            {!readonly && account ? (
              <Lazy>
                <Actions
                  isAdmin={account.isAdmin}
                  record={record}
                  sender={sender}
                  contact={contact}
                />
              </Lazy>
            ) : null}
          </div>

          {hasWarning ? (
            <div styleName="warn-rules">
              🧨 命中预警规则：{record.matchWarnRules.map(v => `「${v}」`).join('')}
            </div>
          ) : null}
        </div>
      </div>
    )}
  </div>
}

function Info<T extends Type>(
  props: Required<Pick<RecordProps<T>, 'contact' | 'record' | 'sender' | 'readonly'>>,
) {
  const { contact, record, sender, readonly } = props

  function triggerSender() {
    if (readonly) return

    // 双击“群成员”名称来 @ 他
    if (
      contact.type === ContactType.group &&
      !record.isSend &&
      record.groupSenderWxid &&
      (record.groupSenderName || sender.name)
    ) {
      triggerAt({
        userId: record.groupSenderWxid,
        name: record.groupSenderName || sender.name,
        avatar: '',
      })
    }
  }

  return <div styleName="record-info">
    <span styleName="sender" onDoubleClick={triggerSender}>
      {sender.name}
    </span>

    {canQuote(record) ? (
      <LazyTooltip title="引用此消息">
        <span styleName="time can-quote" onClick={() => doQuote(record, sender)}>
          {formatChatTime(record.timestamp)}
        </span>
      </LazyTooltip>
    ) : (
      <span styleName="time">{formatChatTime(record.timestamp)}</span>
    )}

    {record.isSend && record.byRobot ? <RobotIcon styleName="robot" /> : null}
    {record.isSend && record.byOpenAPI ? <span styleName="open-api">API</span> : null}
  </div>
}

function CommonExtraInfo<T extends Type>(props: Pick<RecordProps<T>, 'record'>) {
  const { record } = props
  return <>
    {record.isSend && truthy(record.byChatFlow) ? (
      <div className="chat-record-extra-info">由工作流「{record.byChatFlow}」发送</div>
    ) : null}

    {record.isSend && record.byRobot && record.byRobot.hit_node !== 'chatgpt' ? (
      <div className="chat-record-extra-info" styleName="robot-info">
        <div>
          <label>命中意图：</label>
          <span>{record.byRobot.hit_node}</span>
        </div>
        <div>
          <label>命中技能：</label>
          <span>{record.byRobot.hit_title}</span>
        </div>
      </div>
    ) : null}

    {'accountName' in record && truthy(record.accountName) ? (
      <div styleName="from">来自 {record.accountName}</div>
    ) : null}
  </>
}

function SendStatus<T extends Type>(props: Pick<RecordProps<T>, 'record'>) {
  const { record } = props

  function retry() {
    void services.chat.send(record.type, record.content)
  }

  return <>
    {record.isSend ? (
      record.success === null ? (
        <Tooltip title="发送中...">
          <LoadingOutlined styleName="send-confirming" />
        </Tooltip>
      ) : !record.success ? (
        <Tooltip title="发送失败，点击重试">
          <ReloadOutlined onClick={retry} styleName="send-failed" />
        </Tooltip>
      ) : null
    ) : null}

    {record.isSend && record.isRecall === true ? (
      <span styleName="recalled">消息已撤回</span>
    ) : null}
  </>
}
